/*
 * Copyright (C) 2014 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package okhttp3;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import okhttp3.internal.NamedRunnable;
import okhttp3.internal.cache.CacheInterceptor;
import okhttp3.internal.connection.ConnectInterceptor;
import okhttp3.internal.connection.Transmitter;
import okhttp3.internal.http.BridgeInterceptor;
import okhttp3.internal.http.CallServerInterceptor;
import okhttp3.internal.http.RealInterceptorChain;
import okhttp3.internal.http.RetryAndFollowUpInterceptor;
import okhttp3.internal.platform.Platform;
import okio.Timeout;

import static okhttp3.internal.Util.closeQuietly;
import static okhttp3.internal.platform.Platform.INFO;

final class RealCall implements Call {
	//client端
  final OkHttpClient client;

  /**
   * There is a cycle between the {@link Call} and {@link Transmitter} that makes this awkward.
   * This is set after immediately after creating the call instance.
   *  与一个call的实例是互相持有的对方实例
   */
  private Transmitter transmitter;
  //应用级别的 原始request，没有任何重定向 或者验证用的headers
  /** The application's original request unadulterated by redirects or auth headers. */
  final Request originalRequest;
  //判断是否为 webSocket
  final boolean forWebSocket;

  // Guarded by this.
  private boolean executed;

  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
  }

  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
	//之间是互相有引用
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.transmitter = new Transmitter(client, call);
    return call;
  }

  @Override public Request request() {
    return originalRequest;
  }
  /**
   * 在同步的当前线程执行
   */
  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //通知async开始定时任务，在请求超时时取消请求
    transmitter.timeoutEnter();
    //通知监听器
    transmitter.callStart();
    try {
    	//执行时，将当前call放入 dispatcher的同步runningCalls中，方便统一管理
      client.dispatcher().executed(this);
      //执行响应链
      return getResponseWithInterceptorChain();
    } finally {
    	//同步的finished 将当前call传入，从同步队列中移除
      client.dispatcher().finished(this);
    }
  }
  
  /**
   * 用于异步的callback处理
   * 
   */
  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    //通知监听器
    transmitter.callStart();
    //用dispatcher管理异步的callback
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

  @Override public void cancel() {
    transmitter.cancel();
  }

  @Override public Timeout timeout() {
    return transmitter.timeout();
  }

  @Override public synchronized boolean isExecuted() {
    return executed;
  }

  @Override public boolean isCanceled() {
    return transmitter.isCanceled();
  }

  @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
  @Override public RealCall clone() {
    return RealCall.newRealCall(client, originalRequest, forWebSocket);
  }
  /**
   * 用于处理异步call
   *
   */
  final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;
    private volatile AtomicInteger callsPerHost = new AtomicInteger(0);

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    AtomicInteger callsPerHost() {
      return callsPerHost;
    }

    void reuseCallsPerHostFrom(AsyncCall other) {
      this.callsPerHost = other.callsPerHost;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

    /**
     * Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up
     * if the executor has been shut down by reporting the call as failed.
     */
    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
    	  //将当前的 nameRunnable执行起来，
        executorService.execute(this);
        //通知成功
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        transmitter.noMoreExchanges(ioException);
        //通知失败
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
        	//抛出异常也不再执行，直接移除掉
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }

    @Override protected void execute() {
      boolean signalledCallback = false;
      //通知async开始定时任务，在请求超时时取消请求
      transmitter.timeoutEnter();
      try {
    	  //由当前线程池执行
        Response response = getResponseWithInterceptorChain();
        signalledCallback = true;
        //成功时，回调callback
        responseCallback.onResponse(RealCall.this, response);
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
        	//调用失败的callBack
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
    	  //执行后不管成功还是失败，都从队列中移除
        client.dispatcher().finished(this);
      }
    }
  }

  /**
   * Returns a string that describes this call. Doesn't include a full URL as that might contain
   * sensitive information.
   */
  String toLoggableString() {
    return (isCanceled() ? "canceled " : "")
        + (forWebSocket ? "web socket" : "call")
        + " to " + redactedUrl();
  }

  String redactedUrl() {
    return originalRequest.url().redact();
  }

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    //重试之前添加的拦截器，由于 重试层将网络请求全部处理完毕后，才返回；所以是无感知的，用户的拦截器只会得到一个结果
    interceptors.addAll(client.interceptors());
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    //传入内部缓存策略
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
    	//网络层的拦截器，由于在重试层之下；所以，每次的重试重定向都会有感知，并且所以此时用户添加的 网络级别的 拦截器 就会调用多次
      interceptors.addAll(client.networkInterceptors());
    }
    //执行实际的io流，request和resopnse的接收
    interceptors.add(new CallServerInterceptor(forWebSocket));
    System.out.println("getResponseWithInterceptorChain start");
    //定义 串联拦截的链对象，将拦截器串联起来
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
    	//依次执行拦截器
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
      System.out.println("getResponseWithInterceptorChain end");
    }
  }
}
